package com.ls.herostory.channel.handler;

import com.google.protobuf.GeneratedMessageV3;
import com.ls.herostory.cmdhandler.CmdHandler;
import com.ls.herostory.cmdhandler.CmdHandlerFactory;
import com.ls.herostory.msg.GameMsgProtocol;
import com.ls.herostory.session.Session;
import com.ls.herostory.session.SessionUtil;
import com.ls.herostory.thread.MainMsgProcessor;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.socket.nio.NioSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @author liangsu
 * @version v1.0
 * @Description
 * @Date 2020/10/10 13:59
 * @since
 */
public class GameMsgHandler extends SimpleChannelInboundHandler<Object> {

    private final static Logger logger = LoggerFactory.getLogger(GameMsgHandler.class);

    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {

        BroadCast.addChannel(ctx.channel());

        super.channelActive(ctx);
    }

    @Override
    public void handlerRemoved(ChannelHandlerContext ctx) throws Exception {

        // 销毁session
        Session session = SessionUtil.destorySession((NioSocketChannel) ctx.channel());

        BroadCast.removeChannel(ctx.channel());

        if(session != null){
            // 用户退出消息
            GameMsgProtocol.UserQuitResult result = GameMsgProtocol.UserQuitResult.newBuilder()
                    .setQuitUserId(session.getUserId())
                    .build();
            // 广播
            BroadCast.cast(result);
        }

        super.handlerRemoved(ctx);
    }

    protected void channelRead0(ChannelHandlerContext ctx, Object msg) throws Exception {
        logger.info("收到客户端消息, msg = " + msg.toString());

        if(!(msg instanceof GeneratedMessageV3)){
            return;
        }
        GeneratedMessageV3 cmd = (GeneratedMessageV3) msg;

        // 消息处理器
        CmdHandler cmdHandler = CmdHandlerFactory.getHandler(cmd.getClass());

        // 处理消息
        if(cmdHandler != null){
            // 单线程执行业务处理，防止多线程并发的时候的死锁、锁竞争，比如：A砍B的同时B砍A导致死锁
            MainMsgProcessor.getIntance().process(() ->{
                try{
                    cmdHandler.handleCmd(ctx, cmd);
                }catch (Exception e){
                    logger.error(e.getMessage(), e);
                }
            });
        }else{
            logger.error("没有匹配的消息处理器，cmd class name = {}", cmd.getClass().getName());
        }
    }


}
